/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.transport.tcp;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

import cgl.narada.transport.TransportDebugFlags;
import cgl.narada.transport.TransportException;

/**
 * This is used by the broker process to set up a ServerSocket at the port
 * number that is specified. This class accepts connections from clients and and
 * is responsible for passing inbound connection information to the
 * TCPLinkFactory, which then registers the inbound link to its list of managed
 * links.
 * 
 * @author Shrideep Pallickara $Revision $ $Date$
 */

public class TCPServerThread extends Thread implements TransportDebugFlags {

    /**
     * The server socket which is set up when the TCP link factory loads its
     * services
     */
    private ServerSocket serverSocket;

    /* A handle to the TCP link factory */
    private TCPLinkFactory tcpFactory;

    private String moduleName = "TCPServerThread: ";

    private int port;

    public TCPServerThread(int portNum) throws TransportException {
        port = portNum;
        createServerSocket(portNum);
        setPriority(MAX_PRIORITY);
    }

    public TCPServerThread(int portNum, TCPLinkFactory tcpFactory)
        throws TransportException {
        port = portNum;
        if (tcpFactory == null) {
            throw new TransportException(moduleName
                + "The TCPLinkFactory is null");
        }
        this.tcpFactory = tcpFactory;
        createServerSocket(portNum);
    }

    private void createServerSocket(int portNum) throws TransportException {
        try {
            serverSocket = new ServerSocket(portNum);
            if (TCPServerThread_Debug) {
                System.out.println(moduleName
                    + "TCP ServerSocket created on port [" + portNum + "]");
            }
        } catch (IOException ioe) {
            String errorInfo = moduleName
                + "Couldn't create TCPServerSocket on " + "port [" + portNum
                + "]";

            if (TCPServerThread_Debug) {
                System.out.println(errorInfo);
                ioe.printStackTrace();
            }
            throw new TransportException(errorInfo);
        }/* end try-catch */
    }

    public void closeServerSocket() {
        System.out.println(moduleName + "Closing TCP ServeSocket on port ["
            + port + "]");
        try {
            serverSocket.close();
            serverSocket = null;
        } catch (IOException ioe) {
            System.out.println(moduleName + "Problems closing serverSocket "
                + ioe);
            if (TCPServerThread_Debug) {
                ioe.printStackTrace();
            }
        }
    }

    public void run() {
        if (TCPServerThread_Debug) {
            System.out.println(moduleName + "Starting TCPServerThread");
        }
        while (serverSocket != null) {
            try {
                Socket socket = serverSocket.accept();
                socket.setSoLinger(true, 2);
                socket.setTcpNoDelay(true);

                byte tc = 0x08;
                socket.setTrafficClass(tc);

                if (!socket.getKeepAlive()) {
                    socket.setKeepAlive(true);
                    if (TCPServerThread_Debug) {
                        System.out.println(moduleName
                            + "KeepAlive enabled on this socket" + socket
                            + " TcpNODelay = " + socket.getTcpNoDelay()
                            + "SO_TimeOut=" + socket.getSoTimeout() + ", "
                            + "Send Buffer Size=" + socket.getSendBufferSize()
                            + "Traffic class=" + socket.getTrafficClass());
                    }
                }

                tcpFactory.handleInboundTCPLinkRequest(socket);

            } catch (SocketException se) {
                System.out.println(moduleName + "run() " + se);
                break;
            } catch (IOException ioe) {
                System.out.println(moduleName + "run() " + ioe);
                break;
            }/* end try-catch */
        } /* end -while */
        System.out.println(moduleName + "Thread shutting down");
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.out
                .println("Usage: java cgl.narada.transport.tcp.TCPServerThread"
                    + "<port-num>");
            System.exit(0);
        }
        try {
            TCPServerThread serverThread = new TCPServerThread(Integer
                .parseInt(args[0]));
            serverThread.start();
            serverThread.closeServerSocket();
        } catch (TransportException transEx) {
            System.out.println(transEx);
        } /* end try-catch */
    }

}
